#include <iostream>
#include <tuple>
#include <array>
#include <vector>
#include <string>
#include <functional>
#include <cmath>

// 示例函数：三个参数
int add_three(int a, int b, int c) {
  return a + b + c;
}

// 示例函数：不同类型参数
std::string format_info(const std::string& name, int age, double height) {
  return name + " is " + std::to_string(age) + " years old, " +
         std::to_string(height) + " cm tall";
}

// 示例函数：计算距离
double distance(double x1, double y1, double x2, double y2) {
  double dx = x2 - x1;
  double dy = y2 - y1;
  return std::sqrt(dx * dx + dy * dy);
}

// 示例类
class Calculator {
public:
  int multiply(int a, int b, int c) const {
    return a * b * c;
  }

  static double divide(double a, double b) {
    return a / b;
  }
};

void demonstrate_apply() {
  std::cout << "  C++17 std::apply 演示:\n\n";

  // 1. 基本用法：使用tuple调用函数
  std::cout << "  1. 基本用法 - 使用tuple调用函数:\n";

  auto args1 = std::make_tuple(1, 2, 3);
  int result1 = std::apply(add_three, args1);
  std::cout << "    std::apply(add_three, {1, 2, 3}) = " << result1 << "\n";

  // 2. 不同类型参数的函数
  std::cout << "\n  2. 不同类型参数的函数:\n";

  auto args2 = std::make_tuple(std::string("Alice"), 25, 175.5);
  std::string result2 = std::apply(format_info, args2);
  std::cout << "    " << result2 << "\n";

  // 3. 使用array
  std::cout << "\n  3. 使用array:\n";

  std::array<double, 4> coords = {0.0, 0.0, 3.0, 4.0};
  double dist = std::apply(distance, coords);
  std::cout << "    点(0,0)到(3,4)的距离: " << dist << "\n";

  // 4. 使用lambda表达式
  std::cout << "\n  4. 使用lambda表达式:\n";

  auto multiply = [](int a, int b, int c) { return a * b * c; };
  auto args3 = std::make_tuple(2, 3, 4);
  int result3 = std::apply(multiply, args3);
  std::cout << "    lambda(2, 3, 4) = " << result3 << "\n";

  // 5. 调用成员函数
  std::cout << "\n  5. 调用成员函数:\n";

  Calculator calc;
  auto args4 = std::make_tuple(2, 3, 4);
  
  // 调用成员函数需要传入对象指针/引用
  int result4 = std::apply(
    [&calc](int a, int b, int c) { return calc.multiply(a, b, c); },
    args4
  );
  std::cout << "    calc.multiply(2, 3, 4) = " << result4 << "\n";

  // 或者使用std::bind
  auto bound_multiply = std::bind(&Calculator::multiply, &calc,
                                  std::placeholders::_1,
                                  std::placeholders::_2,
                                  std::placeholders::_3);
  int result5 = std::apply(bound_multiply, args4);
  std::cout << "    使用bind: " << result5 << "\n";

  // 6. 调用静态成员函数
  std::cout << "\n  6. 调用静态成员函数:\n";

  auto args5 = std::make_tuple(10.0, 2.0);
  double result6 = std::apply(Calculator::divide, args5);
  std::cout << "    Calculator::divide(10.0, 2.0) = " << result6 << "\n";

  // 7. 使用结构化绑定获取返回值
  std::cout << "\n  7. 使用结构化绑定处理返回值:\n";

  auto make_point = [](int x, int y) {
    return std::make_pair(x, y);
  };

  auto args6 = std::make_tuple(5, 10);
  auto [x, y] = std::apply(make_point, args6);
  std::cout << "    点坐标: (" << x << ", " << y << ")\n";

  // 8. 复杂示例：函数式编程风格
  std::cout << "\n  8. 复杂示例 - 函数式编程风格:\n";

  // 定义多个函数
  auto square = [](int x) { return x * x; };
  auto add = [](int a, int b) { return a + b; };
  auto multiply2 = [](int a, int b) { return a * b; };

  // 链式调用
  auto args7 = std::make_tuple(3, 4);
  int result7 = std::apply(
    [&square, &add](int a, int b) {
      return add(square(a), square(b));
    },
    args7
  );
  std::cout << "    3^2 + 4^2 = " << result7 << "\n";

  // 9. 处理空tuple
  std::cout << "\n  9. 处理无参数函数:\n";

  auto get_answer = []() { return 42; };
  std::tuple<> empty_args;
  int answer = std::apply(get_answer, empty_args);
  std::cout << "    答案: " << answer << "\n";

  // 10. 实际应用：配置解析
  std::cout << "\n  10. 实际应用 - 配置解析:\n";

  auto create_config = [](const std::string& host, int port, bool ssl) {
    return "配置: " + host + ":" + std::to_string(port) +
           (ssl ? " (SSL)" : " (非SSL)");
  };

  auto config_args = std::make_tuple(std::string("localhost"), 8080, true);
  std::string config = std::apply(create_config, config_args);
  std::cout << "    " << config << "\n";

  // 11. 与模板结合
  std::cout << "\n  11. 与模板结合:\n";

  auto process = [](auto... args) {
    return (args + ...);  // 折叠表达式
  };

  auto args8 = std::make_tuple(1, 2, 3, 4, 5);
  int sum = std::apply(process, args8);
  std::cout << "    求和(1,2,3,4,5) = " << sum << "\n";

  // 12. 优势说明
  std::cout << "\n  std::apply 的优势:\n";
  std::cout << "  - 统一处理tuple和array作为函数参数\n";
  std::cout << "  - 支持可变参数模板\n";
  std::cout << "  - 简化函数式编程风格\n";
  std::cout << "  - 与结构化绑定配合良好\n";
  std::cout << "  - 类型安全，编译期检查\n";
}

